package network;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

//进行TCP协议下的服务器相关的使用；
public class TcpEchoServer {
    private ServerSocket serverSocket = null;

    //进行服务器得构建需要进行端口的设置，方便客户端进行正确的请求发送；
    public TcpEchoServer(int port) throws IOException {
        serverSocket = new ServerSocket(port);
    }

    //进行服务器的启动工作；
    public void start() throws IOException {
        System.out.println("启动服务器");
        ExecutorService executorService= Executors.newCachedThreadPool();
        while (true) {
            //启动服务器后需要进行相关的连接操作；
            //要想进行服务器于客户端的通信需要进行连接，否则无法完成请求与回应操作；
            Socket clientSocket = serverSocket.accept();//进行与客户端的连接操作；
            //进行进行完成连接操作；
            //1.请求的获取；
            //2.请求的解析；
            //3.返回响应；
            //进行修改操作：使用多线程的引入；进而完成一个服务器可以进行接收多个客户端的请求；
            //方法一：多线程的使用；
            //Thread thread=new Thread(()->{
              //  try {
                //    processConnection(clientSocket);
                //} catch (IOException e) {
                 //   throw new RuntimeException(e);
               // }
            //});
            //thread.start();//线程的启动；
            //方法二：进行线程池的使用
           executorService.submit(()->{
               try {
                   processConnection(clientSocket);
               } catch (IOException e) {
                   throw new RuntimeException(e);
               }
           });
        }
    }
    private void processConnection(Socket clientSocket) throws IOException {
        System.out.printf("[%s:%d] 客户端上线!\n",clientSocket.getInetAddress(),clientSocket.getPort());
        //因为TCP协议下接收的文件是字节类型的文件；
        //所以可以采用文件的输入与输出流进行相关的操作；
        try(InputStream inputStream=clientSocket.getInputStream();
                OutputStream outputStream=clientSocket.getOutputStream()) {
            //针对这两个操作类进行套接一层，进而方便进行相关的操作；
            Scanner scanner=new Scanner(inputStream);
            //输出操作：不仅可以进行获取控制台的内容，也可以进行获取客户端发来的请求内容；
            PrintWriter writer=new PrintWriter(outputStream);
            //同样的操作这个类的运用就可以进行写入文件操作，可以将服务器的响应内容进行写入内存；
            //但是：在此处需要进行注意：此出只是将响应的内容，写入到了缓冲区中，没有真正的写入到内存中；
            //所以进行运行客户端的时候就会无法收到服务器得回应；
            //这是就需要在后续进行相关的操作；
            //将写入到缓冲区的内容传递到内存中去；
            while(true){
                //进行请求的解析操作；
                //通过scanner进行解析操作；
                if(!scanner.hasNext()){
                    System.out.printf("[%s:%d] 客户端上线!\n",clientSocket.getInetAddress(),clientSocket.getPort());
                    break;
                }
                String request=scanner.next();//获取请求内容；
                String response=process(request);//根据请求计算响应；
                //将响应数据返回到客户端；
                writer.println(response);//此处只是将数据写入到了缓冲区中去了；
                writer.flush();//将写入缓冲区的数据推入到内存中去；
                //接下来进行服务器中日志的打印；
                System.out.printf("[%s:%d] req: %s, resp: %s\n",
                        clientSocket.getInetAddress()
                ,clientSocket.getPort(),request,response);

            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            clientSocket.close();
        }
    }
    private String process(String request){
        return request;
    }
    public static void main(String[] args) throws IOException {
        TcpEchoServer server=new TcpEchoServer(9090);
        server.start();
    }
}
